{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TVM Runtime api\n",
    "\n",
    "源码见：`tvm/src/runtime/c_runtime_api.h`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`tvm/runtime/c_runtime_api.h` 包含了 TVM 运行时库的一些函数和宏定义。\n",
    "\n",
    "TVM 项目的理念是定制编译阶段以生成可以透明地被其他项目使用的代码。因此，这个头文件中包含了一些最小的运行时代码粘合以及有限的内存管理代码，以便进行快速测试。\n",
    "\n",
    "运行时 API 独立于 TVM 编译堆栈，可以通过链接 `libtvm_runtime` 来使用。\n",
    "\n",
    "常见的流程如下：\n",
    "\n",
    "- 使用 `TVMFuncListGlobalNames` 获取全局函数名称\n",
    "- 使用 `TVMFuncCall` 调用这些函数\n",
    "\n",
    "API函数的可能返回值有：\n",
    "- `0`：成功\n",
    "- `-1`：错误可以通过 `TVMGetLastError` 检索\n",
    "- `-2`：前端发生错误并记录在前端"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```cpp\n",
    "// Macros to do weak linking\n",
    "#ifdef _MSC_VER\n",
    "#define TVM_WEAK __declspec(selectany)\n",
    "#else\n",
    "#define TVM_WEAK __attribute__((weak))\n",
    "#endif\n",
    "```\n",
    "\n",
    "这段代码是 C++ 头文件中的宏定义，用于控制 TVM 库在不同编译器环境下进行弱链接的方式。\n",
    "\n",
    "首先，`#ifdef _MSC_VER` 检查是否使用的是 Microsoft Visual C++ 编译器（即 Windows 平台）。如果是，那么使用 `__declspec(selectany)` 来声明弱符号。`__declspec(selectany)` 是 Visual C++ 特有的关键字，用于指示编译器在多个目标文件中选择一个符号的定义，而不是报错。\n",
    "\n",
    "如果不是 Visual C++ 编译器，那么使用 `__attribute__((weak))` 来声明弱符号。这是 GCC 和 Clang 编译器的一种方式，用于设置符号为弱符号。弱符号允许在链接时被其他同名强符号覆盖，如果没有找到强符号，则使用弱符号作为备选。\n",
    "\n",
    "通过这样的宏定义，TVM库可以在不同编译器环境下灵活地进行弱链接，以支持跨平台的编译和链接。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```cpp\n",
    "#ifdef __EMSCRIPTEN__\n",
    "#include <emscripten/emscripten.h>\n",
    "#define TVM_DLL EMSCRIPTEN_KEEPALIVE\n",
    "#endif\n",
    "```\n",
    "\n",
    "这段代码是 C++ 头文件中的宏定义，用于在 Emscripten 编译器环境下控制 TVM 库的导出方式。\n",
    "\n",
    "首先，`#ifdef __EMSCRIPTEN__` 检查是否使用的是 Emscripten 编译器。Emscripten 是一个将 C/C++ 代码编译成 JavaScript 的工具链，通常用于 Web 开发。\n",
    "\n",
    "如果当前是 Emscripten 编译器环境，那么包含 `<emscripten/emscripten.h>` 头文件，这是 Emscripten 提供的一组 API 函数和宏定义。\n",
    "\n",
    "接下来，使用 `#define TVM_DLL EMSCRIPTEN_KEEPALIVE` 来声明 TVM 库中的符号为保持活跃状态。`EMSCRIPTEN_KEEPALIVE` 是 Emscripten 提供的一个宏，用于告诉编译器不要优化掉这个符号，确保它在运行时可用。这对于需要在 JavaScript 环境中调用的函数或变量非常有用。\n",
    "\n",
    "通过这样的宏定义，TVM 库可以在 Emscripten 编译器环境下正确地导出符号，以便在 Web 环境中使用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```cpp\n",
    "// helper macro to suppress unused warning\n",
    "#if defined(__GNUC__)\n",
    "#define TVM_ATTRIBUTE_UNUSED __attribute__((unused))\n",
    "#else\n",
    "#define TVM_ATTRIBUTE_UNUSED\n",
    "#endif\n",
    "```\n",
    "\n",
    "这段代码是 C 语言的宏定义，用于在编译时抑制未使用变量或函数的警告。它使用了条件编译来检查是否使用的是 GNU 编译器（如 GCC）。如果是，则定义名为 `TVM_ATTRIBUTE_UNUSED` 的宏，该宏带有 `__attribute__((unused))` 属性，告诉编译器这个变量或函数可能不会被使用，从而避免产生未使用的警告。如果不是 GNU 编译器，则简单地定义 `TVM_ATTRIBUTE_UNUSED` 为空。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```cpp\n",
    "#ifndef TVM_DLL\n",
    "#ifdef _WIN32\n",
    "#ifdef TVM_EXPORTS\n",
    "#define TVM_DLL __declspec(dllexport)\n",
    "#else\n",
    "#define TVM_DLL __declspec(dllimport)\n",
    "#endif\n",
    "#else\n",
    "#define TVM_DLL __attribute__((visibility(\"default\")))\n",
    "#endif\n",
    "#endif\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这段代码是 C++ 头文件中的宏定义，用于控制 TVM 库在不同平台和编译环境下的动态链接库（DLL）导出方式。\n",
    "\n",
    "首先，`#ifndef TVM_DLL` 检查是否已经定义了 `TVM_DLL` 这个宏。如果没有定义，那么继续执行下面的代码块。\n",
    "\n",
    "接下来，`#ifdef _WIN32` 检查当前是否是 Windows 平台。如果是 Windows 平台，再进一步检查 `TVM_EXPORTS` 宏是否被定义。\n",
    "\n",
    "- 如果 `TVM_EXPORTS` 被定义，说明我们正在构建 TVM 库本身，需要将函数或变量导出为 DLL 接口，因此使用 `__declspec(dllexport)` 来声明。\n",
    "- 如果 `TVM_EXPORTS` 没有被定义，说明我们正在使用 TVM 库，需要导入库中的函数或变量，因此使用 `__declspec(dllimport)` 来声明。\n",
    "\n",
    "如果不是 Windows 平台，那么使用 `__attribute__((visibility(\"default\")))` 来声明，这是 GCC 编译器的一种方式，用于设置符号的可见性。在这种情况下，默认情况下所有符号都是可见的。\n",
    "\n",
    "最后，如果 `TVM_DLL` 已经被定义，那么这个宏定义块不会再次执行，避免了重复定义的问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```cpp\n",
    "#ifdef __cplusplus\n",
    "extern \"C\" {\n",
    "#endif\n",
    "// 函数原型等内容\n",
    "#ifdef __cplusplus\n",
    "}  // TVM_EXTERN_C\n",
    "#endif\n",
    "```\n",
    "\n",
    "这段代码是 C++ 头文件中的宏定义，用于控制 TVM 库在不同编译器环境下进行 C 语言链接的方式。\n",
    "\n",
    "首先，`#ifdef __cplusplus` 检查是否使用的是 C++ 编译器。如果是，那么使用 `extern \"C\"` 来声明一个 C 语言链接区块。这是为了确保在这个区块中的函数和变量遵循 C 语言的命名规则和调用约定，而不是 C++ 的规则。\n",
    "\n",
    "接下来，可以在这个区块中添加函数原型、类型定义等 C 语言相关的代码。这些代码将被编译器视为 C 语言代码，并按照 C 语言的方式进行编译和链接。\n",
    "\n",
    "最后，再次使用 `#ifdef __cplusplus` 来结束 C 语言链接区块，并在结束时加上 `} // TVM_EXTERN_C` 注释，以便于阅读和维护代码。\n",
    "\n",
    "通过这样的宏定义，TVM 库可以在不同编译器环境下灵活地进行 C 语言链接，以支持跨平台的编译和链接。"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
